from androguard.misc import AnalyzeAPK
import hashlib
import zipfile

sample_path = "./sample_apk/000db93ae6b67e6303e5b5b4839df016.apk"

class Myapk():
    def __init__(self, permission, apk_class, library, interface, methods):
        self.permission = permission
        self.apk_class = apk_class
        self.library = library
        self.interface = interface
        self.methods = methods
        self.per_vector = []
        self.cla_vector = []
        self.lib_vector = []
        self.int_vector = []
        self.met_vector = [] 

def get_str_md5(content):
    """
    计算字符串md5
    :param content:
    :return:
    """
    m = hashlib.md5(content) #创建md5对象
    return m.hexdigest()


def get_libso(apk_path):
    '''
    Fuck lxy because he put global variable in function and never add a comment
    
    with zipfile.ZipFile(file=sample_path, mode='r') as zf:
    '''
    with zipfile.ZipFile(file=apk_path, mode='r') as zf:
        library_md5 = []
        for old_name in zf.namelist():
            # 由于源码遇到中文是cp437方式，所以解码成gbk，windows即可正常
            new_name = old_name.encode('cp437').decode('gbk')
            # 判断文件是文件夹还是文件

            if old_name.endswith(".so"):
                # zf.read 是读取压缩包里的文件内容
                file_content = zf.read(old_name)
                file_md5 = get_str_md5(file_content)
                #print(old_name, " -> ", file_md5)
                library_md5.append(file_md5)
        return list(set(library_md5))


def get_interface(dx):
    interface = []
    for i in dx.get_classes():
        interface.extend(i.implements)
    return list(set(interface))


def process_apk(apk_path, per_dict, cla_dict, lib_dict, int_dict, met_dict):
    a, d, dx = AnalyzeAPK(apk_path)
    # feature list
    permission_dict = a.get_details_permissions()

    permission_key = list(permission_dict.keys())
    permission_value = []
    for item in permission_key:
        if item not in per_dict.keys():
            per_dict[item] = len(per_dict.keys())
        permission_value.append(per_dict[item])
    
    apk_class_key = list(dx.get_classes())
    apk_class_key = [x.name for x in apk_class_key]
    apk_class_value = []
    for item in apk_class_key:
        if item not in cla_dict.keys():
            cla_dict[item] = len(cla_dict.keys())
        apk_class_value.append(cla_dict[item])
            
    library_key = get_libso()
    library_value = []
    for item in library_key:
        if item not in lib_dict.keys():
            lib_dict[item] = len(lib_dict.keys())
        library_value.append(lib_dict[item])
            
    interface_key = get_interface(dx)
    interface_value = []
    for item in interface_key:
        if item not in int_dict.keys():
            int_dict[item] = len(int_dict.keys())
        interface_value.append(int_dict[item])
            
    methods_key = [x for x in dx.get_methods()]
    methods_key = [(x.class_name, x.name) for x in methods_key]
    methods_value = []
    for item in methods_key:
        if item not in met_dict.keys():
            met_dict[item] = len(met_dict.keys())
        methods_value.append(met_dict[item])
    
    
    #print(apk_path +" Done!")
    return Myapk(permission_value, apk_class_value, library_value, interface_value, methods_value)


def process_apk_lib(apk_path, lib_dict):
    try:
        # feature list
        library_key = get_libso(apk_path)
        library_value = []
        for item in library_key:
            if item not in lib_dict.keys():
                lib_dict[item] = len(lib_dict.keys())
            library_value.append(lib_dict[item])

        #print(apk_path +" Done!")
        return Myapk([], [], library_value, [], [])
    
    except Exception as e:
        print(e)
        return Myapk([], [], [], [], [])
